package ar.uba.fi.algo3.tp3.modelo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

public class BuscadorDeCaminos {

    public static Ruta buscarCamino(Mapa mapa, int xOrig, int yOrig, int xDest, int yDest) {
        xOrig = Math.round(xOrig / 30) * 30;
        yOrig = Math.round(yOrig / 30) * 30;
        xDest = Math.round(xDest / 30) * 30;
        yDest = Math.round(yDest / 30) * 30;

        boolean llegoADestino = false;
        List<PuntoCalculo> l = new ArrayList<PuntoCalculo>();
        l.add(new PuntoCalculo(xDest, yDest));

        while (!llegoADestino) {
            boolean recomenzarIteracion = false;
            for (Iterator<PuntoCalculo> it = l.iterator(); !llegoADestino && !recomenzarIteracion && it.hasNext();) {
                PuntoCalculo puntoCalculo = it.next();
                List<PuntoCalculo> listaAux = new ArrayList<PuntoCalculo>();
                listaAux.add(new PuntoCalculo(puntoCalculo.getX(), puntoCalculo.getY() - 30, puntoCalculo.getContador() + 1));
                listaAux.add(new PuntoCalculo(puntoCalculo.getX(), puntoCalculo.getY() + 30, puntoCalculo.getContador() + 1));
                listaAux.add(new PuntoCalculo(puntoCalculo.getX() - 30, puntoCalculo.getY(), puntoCalculo.getContador() + 1));
                listaAux.add(new PuntoCalculo(puntoCalculo.getX() + 30, puntoCalculo.getY(), puntoCalculo.getContador() + 1));

                for (Iterator<PuntoCalculo> itAux = listaAux.iterator(); !llegoADestino && itAux.hasNext();) {
                    PuntoCalculo puntoCalculoAux = itAux.next();
                    if (puntoCalculoAux.getX() == xOrig && puntoCalculoAux.getY() == yOrig) {
                        llegoADestino = true;
                    }
                    if (esPuntoValido(mapa, puntoCalculoAux)) {
                        if (!l.contains(puntoCalculoAux)) {
                            recomenzarIteracion = true;
                            l.add(puntoCalculoAux);
                        } else {
                            int indice = l.indexOf(puntoCalculoAux);
                            PuntoCalculo actual = l.get(indice);
                            if (actual.getContador() > puntoCalculoAux.getContador()) {
                                l.add(puntoCalculoAux);
                                recomenzarIteracion = true;
                            }
                        }
                    }

                }
            }
        }

        Collections.reverse(l);
        return listaPuntosCalculoARuta(l);
    }

    private static Ruta listaPuntosCalculoARuta(List<PuntoCalculo> l) {
        Ruta r = new Ruta();

        PuntoCalculo primero = l.get(0);

        PuntoCalculo ultimoInsertado = primero;
        for (Iterator<PuntoCalculo> it = l.iterator(); it.hasNext();) {
            PuntoCalculo puntoCalculo = it.next();
            if (puntoCalculo.esVecinoA(ultimoInsertado)) {
                r.agregarPunto(puntoCalculo.getX(), puntoCalculo.getY());
                ultimoInsertado = puntoCalculo;
            }
        }
        return r;
    }

    private static boolean esPuntoValido(Mapa m, PuntoCalculo pc) {
        int x = pc.getX();
        int y = pc.getY();
        if (x > 480 || y > 450) {
            return false;
        }
        return !m.hayPared(x, y);
    }
}
